import os
import datetime
from typing import Dict, List
from openpyxl import load_workbook, Workbook
from openpyxl.drawing.image import Image
from enum import Enum

from typing_extensions import override

from utils.file_util import init_output_dir, get_output_dir, get_screenshot_dir, rename
from utils.shell_util import kill_current_app
from mobileagent.mobile_agent import MobileAgent


class CasePropertyEnum(Enum):
    def __init__(self, column: str, index: int) -> None:
        self.column = column
        self.index = index

    NAME = "C", 3
    SETUP_STEP = "K", 11
    STEP = "L", 12
    ASSERT = "M", 13
    RESULT = "P", 16
    COST = "Q", 17
    SCREENSHOT = "R", 18
    RECORD = "S", 19


split_text = '<br>'


class Step:
    operation = ''
    log = ''
    cost = 0
    result = ''
    screenshot = ''

    def __init__(self, operation):
        self.operation = operation

    def run_step(self, agent):
        before_time = datetime.datetime.now()
        self.log = agent.run(self.operation)
        # step['log'] = exec_python([ 'Mobile-Agent-v2/mobile_agent.py', output_path, step['step']])
        after_time = datetime.datetime.now()
        self.cost = (after_time - before_time).seconds
        if self.log:
            result = self.log.strip().rsplit('\n', 1)[1]
            if 'Step result' in result:
                result = result.split(':')[1].strip()
            else:
                result = 'Unknown'
        else:
            result = 'Unknown'
        self.result = result


class SetUp(Step):

    @override
    def run_step(self, agent):
        self.cost = 0
        if '清理当前应用' in self.operation:
            self.log = kill_current_app()
            self.result = 'Succeed'
        else:
            super().run_step(agent)


class Case:
    name = ''
    expectation = ''
    setup_steps = List[SetUp]
    steps = List[Step]

    def __init__(self, name, expectation):
        self.name = name
        self.expectation = expectation
        self.setup_steps = []
        self.steps = []

class UiAutoTest:

    @classmethod
    def run(cls, input_file: str):
        # 创建测试任务结果存放路径
        job_id, output_file = cls.init_task(input_file)

        if input_file == output_file:
            # 解析xlsx文件，提取测试步骤
            test_cases = cls.load_test_cases(input_file)
        else:
            # 解析xlsx文件，测试步骤按行填充，并将结果文件写入目标路径
            test_cases = cls.parse_test_cases(input_file, output_file)

        print(test_cases)

        # 测试执行
        test_cases = cls.run_test(job_id, test_cases)

        # 结果导入xlsx文件
        cls.export_results(test_cases, output_file)

    @staticmethod
    def init_task(input_file:str):
        job_id = os.path.split(input_file)[1].rsplit('.', 1)[0]
        output_dir = init_output_dir(job_id)
        output_file = os.path.join(output_dir, '{}.xlsx'.format(job_id))
        return job_id, output_file

    @staticmethod
    def run_step(agent, step):
        before_time = datetime.datetime.now()
        step.log = agent.run(step.operation)
        # step['log'] = exec_python([ 'Mobile-Agent-v2/mobile_agent.py', output_path, step['step']])
        after_time = datetime.datetime.now()
        step.cost = (after_time - before_time).seconds
        if step.log:
            result = step.log.strip().rsplit('\n', 1)[1]
            if 'Step result' in result:
                result = result.split(':')[1].strip()
            else:
                result = 'Unknown'
        else:
            result = 'Unknown'
        step.result = result

    @classmethod
    def run_test(cls, job_id, cases_info):
        output_path = get_output_dir(job_id)
        screenshot_path = os.path.join(get_screenshot_dir(output_path),'screenshot.jpg')
        # kill_current_app()
        agent = MobileAgent(output_path)
        for case in cases_info:
            for step_index, step in enumerate(case.setup_steps + case.steps, 1):
                step.screenshot = os.path.join(get_screenshot_dir(output_path),
                                               '{}_{}_screenshot.jpg'.format(case.name, step_index))
                # cls.run_step(agent, step)
                step.run_step(agent)
                rename(screenshot_path, step.screenshot)
                if step.result != 'Succeed':
                    print('用例：{}\n步骤：{}\n运行失败'.format(case.name, step.operation))
                    break
            # TODO 每一条用例测试结束后需要还原环境
            # kill_current_app()
        return cases_info

    @staticmethod
    def load_test_cases(input_xlsx):
        wb = load_workbook(input_xlsx)
        ws = wb.active

        cases_info = []
        for index, row in enumerate(ws.iter_rows(min_row=2),2):  # 从第二行开始，跳过表头
            case_name = row[CasePropertyEnum.NAME.index - 1].value
            if case_name:
                case_assert = row[CasePropertyEnum.ASSERT.index - 1].value
                # case = {'name': '{}-{}'.format(index, case_name), 'assert': case_assert, 'steps': []}
                case = Case(name = '{}-{}'.format(index, case_name),
                            expectation = case_assert)

                setup_steps_count = len(row[CasePropertyEnum.SETUP_STEP.index - 1].value.split(split_text))
                steps_count = len(row[CasePropertyEnum.STEP.index - 1].value.split(split_text))
                for cell in ws[CasePropertyEnum.RESULT.column][index : index + setup_steps_count+ steps_count]:
                    if not cell.value:
                        setup_steps = row[CasePropertyEnum.SETUP_STEP.index - 1].value  # 获取“预置条件”列的内容
                        steps = row[CasePropertyEnum.STEP.index - 1].value  # 获取“用例步骤”列的内容
                        if setup_steps:
                            case.setup_steps = [SetUp(operation=operation) for operation in setup_steps.split(split_text)]  # 按照<br>分隔步骤
                        if steps:
                            case.steps = [Step(operation=operation) for operation in steps.split(split_text)]  # 按照<br>分隔步骤
                        break
                cases_info.append(case)

        wb.close()
        return cases_info

    @staticmethod
    def parse_test_cases(input_xlsx, output_xlsx):
     # 读取原始XLSX文件
        wb = load_workbook(input_xlsx)
        ws = wb.active

        new_wb = Workbook()
        new_ws = new_wb.active

        # 获取标题行
        headers = [cell.value for cell in ws[1]]
        headers += ['测试结果','运行时长' ,'结果截图', '操作记录']
        new_ws.append(headers)

        cases_info = []

        for row in ws.iter_rows(min_row=2):  # 从第二行开始，跳过表头
            new_row = [cell.value for cell in row]
            new_ws.append(new_row)
            # case = {'name': '{}-{}'.format(new_ws.max_row + 1, row[CasePropertyEnum.NAME.index - 1].value),
            #         'assert': row[CasePropertyEnum.ASSERT.index - 1].value,
            #         'setup_steps': [],
            #         'steps': []}
            case = Case(name='{}-{}'.format(new_ws.max_row, row[CasePropertyEnum.NAME.index - 1].value),
                        expectation=row[CasePropertyEnum.ASSERT.index - 1].value)

            setup_steps = row[CasePropertyEnum.SETUP_STEP.index - 1].value  # 获取“预置条件”列的内容
            steps = row[CasePropertyEnum.STEP.index - 1].value  # 获取“用例步骤”列的内容
            if setup_steps:
                setup_step_list = setup_steps.split(split_text)
                # 将每个步骤和原有行的内容组合
                for operation in setup_step_list:
                    new_row = [None] * CasePropertyEnum.SETUP_STEP.index  # 复制当前行
                    new_row[CasePropertyEnum.SETUP_STEP.index - 1] = operation.strip()  # 更新为当前步骤
                    new_ws.append(new_row)  # 收集新行
                    case.setup_steps.append(SetUp(operation = operation))
            if steps:
                step_list = steps.split(split_text)  # 按照<br>分隔步骤
                # 将每个步骤和原有行的内容组合
                for operation in step_list:
                    new_row = [None] * CasePropertyEnum.STEP.index  # 复制当前行
                    new_row[CasePropertyEnum.STEP.index - 1] = operation.strip()  # 更新为当前步骤
                    new_ws.append(new_row)  # 收集新行
                    case.steps.append(Step(operation=operation))

            if case.setup_steps or case.steps:
                cases_info.append(case)

        # 保存新的XLSX文件
        new_wb.save(output_xlsx)
        new_wb.close()
        wb.close()

        return cases_info

    @staticmethod
    def export_results(cases_info:list[Case], output_xlsx):
        wb = load_workbook(output_xlsx)
        ws = wb.active

        for case in cases_info:
            case_row, case_name = case.name.split('-',1)
            if ws[CasePropertyEnum.NAME.column + case_row].value == case_name:
                for index, step in enumerate(case.setup_steps + case.steps, 1):
                    step_row = str(int(case_row) + index)
                    if step.result:
                        ws[CasePropertyEnum.RESULT.column + step_row].value = step.result
                        ws[CasePropertyEnum.RECORD.column + step_row].value = step.log
                        ws[CasePropertyEnum.COST.column + step_row].value = step.cost
                        if os.path.exists(step.screenshot):
                            image = Image(step.screenshot)
                            image.width = image.width // 20
                            image.height = image.height // 20
                            # 设置单元格行高
                            ws.row_dimensions[int(step_row)].height = max(ws.row_dimensions[int(step_row)].height,image.height) \
                                if ws.row_dimensions[int(step_row)].height else image.height

                            ws.add_image(image, CasePropertyEnum.SCREENSHOT.column + step_row)
                    else:
                        print('用例：{} 步骤：{} 未执行'.format(case.name, step.operation))
            else:
                print('未找到测试用例：', case_name)

            wb.save(output_xlsx)
            wb.close()

